#include "interfaces.h"
#include <string>
#include <cstdarg>
#include <iostream>
#include <vector>

class CConVar : public IConVar {
private:
    std::string name;
    std::string description;
    std::string stringValue;
    int intValue;
    float floatValue;
    bool boolValue;
    ConVarType type;
    int flags;

public:
    CConVar(const char* varName, const char* varDesc, int defaultValue, int varFlags = 0)
        : name(varName), description(varDesc), intValue(defaultValue),
        floatValue(static_cast<float>(defaultValue)), boolValue(defaultValue != 0),
        type(CVAR_TYPE_INT), flags(varFlags) {
        stringValue = std::to_string(defaultValue);
    }

    CConVar(const char* varName, const char* varDesc, float defaultValue, int varFlags = 0)
        : name(varName), description(varDesc), intValue(static_cast<int>(defaultValue)),
        floatValue(defaultValue), boolValue(defaultValue != 0.0f),
        type(CVAR_TYPE_FLOAT), flags(varFlags) {
        stringValue = std::to_string(defaultValue);
    }

    CConVar(const char* varName, const char* varDesc, const char* defaultValue, int varFlags = 0)
        : name(varName), description(varDesc), stringValue(defaultValue),
        intValue(0), floatValue(0.0f), boolValue(false),
        type(CVAR_TYPE_STRING), flags(varFlags) {
    }

    CConVar(const char* varName, const char* varDesc, bool defaultValue, int varFlags = 0)
        : name(varName), description(varDesc), intValue(defaultValue ? 1 : 0),
        floatValue(defaultValue ? 1.0f : 0.0f), boolValue(defaultValue),
        type(CVAR_TYPE_BOOL), flags(varFlags) {
        stringValue = defaultValue ? "1" : "0";
    }

    // IConVar implementation
    const char* GetName() const override { return name.c_str(); }
    const char* GetDescription() const override { return description.c_str(); }

    int GetInt() const override { return intValue; }
    float GetFloat() const override { return floatValue; }
    const char* GetString() const override { return stringValue.c_str(); }
    bool GetBool() const override { return boolValue; }

    void SetValue(int value) override {
        intValue = value;
        floatValue = static_cast<float>(value);
        boolValue = value != 0;
        stringValue = std::to_string(value);
        type = CVAR_TYPE_INT;
    }

    void SetValue(float value) override {
        floatValue = value;
        intValue = static_cast<int>(value);
        boolValue = value != 0.0f;
        stringValue = std::to_string(value);
        type = CVAR_TYPE_FLOAT;
    }

    void SetValue(const char* value) override {
        stringValue = value;
        // Try to parse as number
        try {
            floatValue = std::stof(value);
            intValue = static_cast<int>(floatValue);
            boolValue = floatValue != 0.0f;
        }
        catch (...) {
            floatValue = 0.0f;
            intValue = 0;
            boolValue = false;
        }
        type = CVAR_TYPE_STRING;
    }

    void SetValue(bool value) override {
        boolValue = value;
        intValue = value ? 1 : 0;
        floatValue = value ? 1.0f : 0.0f;
        stringValue = value ? "1" : "0";
        type = CVAR_TYPE_BOOL;
    }

    ConVarType GetType() const override { return type; }
    bool IsFlagSet(int flag) const override { return (flags & flag) != 0; }
};


class CCVarSystem :
    public ICVarSystem {
private:
    std::vector<IConVar*> conVars;

public:
    ~CCVarSystem() override {
        for (auto conVar : conVars) {
            delete conVar;
        }
        conVars.clear();
    }

    IConVar* FindVar(const char* name) override {
        if (!name) return nullptr;

        std::string searchName(name);
        for (auto conVar : conVars) {
            if (conVar && conVar->GetName() &&
                std::string(conVar->GetName()) == searchName) {
                return conVar;
            }
        }
        return nullptr;
    }

    void RegisterConCommand(IConVar* conVar) override {
        if (!conVar) return;

        for (auto existing : conVars) {
            if (existing == conVar) {
                return;
            }
        }

        conVars.push_back(conVar);
    }

    void UnregisterConCommand(IConVar* conVar) override {
        if (!conVar) return;

        for (auto it = conVars.begin(); it != conVars.end(); ++it) {
            if (*it == conVar) {
                conVars.erase(it);
                delete conVar;
                break;
            }
        }
    }

    void Print(const char* format, ...) override {
        va_list args;
        va_start(args, format);
        vprintf(format, args);
        va_end(args);
        printf("\n");
    }

    void PrintError(const char* format, ...) override {
        va_list args;
        va_start(args, format);
        fprintf(stderr, "Error: ");
        vfprintf(stderr, format, args);
        va_end(args);
        fprintf(stderr, "\n");
    }
};